package ar.edu.unq.tpi.uis.dominio;

import com.db4o.ObjectSet;

import ar.edu.unq.tpi.uis.tepe3.dominio.Folder;
import ar.edu.unq.tpi.uis.tepe3.dominio.Group;
import ar.edu.unq.tpi.uis.tepe3.dominio.SvnManager;
import ar.edu.unq.tpi.uis.tepe3.dominio.User;
import ar.edu.unq.tpi.uis.tepe3.dominio.exception.PersistenceException;
import ar.edu.unq.tpi.uis.tepe3.dominio.exception.UserCantBeCreated;
import ar.edu.unq.tpi.uis.tepe3.dominio.persistence.Db4oPersistence;
import junit.framework.TestCase;

public class PersistenceTestCase extends TestCase {
	
	private Db4oPersistence db;

	@Override
	protected void setUp() throws Exception {
		this.db = Db4oPersistence.getInstance();
		
		SvnManager aSvnManager = new SvnManager();
		aSvnManager.addUser(new User("Foo, Bar", "foo", "1234"));
		aSvnManager.addUser(new User("Bar, Foo", "bar", "4321"));
		aSvnManager.addGroup(new Group("Groupo Foo1"));
		aSvnManager.addGroup(new Group("Groupo Foo2"));
		aSvnManager.addGroup(new Group("Groupo Foo3"));
		aSvnManager.addGroup(new Group("Groupo Bar1"));
		aSvnManager.getFileSystem().addChild(new Folder("home"));
		aSvnManager.getFileSystem().addChild(new Folder("tmp"));
		aSvnManager.getFileSystem().addChild(new Folder("var"));
		
		this.db.save(aSvnManager);
	}

	@Override
	protected void tearDown() throws Exception {
		ObjectSet<SvnManager> results = this.db.fetchAll();
		SvnManager aSvnManager;
		
		while(results.hasNext()){
			aSvnManager = results.next();
			this.db.delete(aSvnManager);
		}
	}
	
	// **********************************
	// ** Test Cases
	// **********************************
	
	public void testSaveAndFetchAll(){
		ObjectSet<SvnManager> results = this.db.fetchAll();
		
		assertsForFetchTests(results);
	}
	
	public void testSaveAndFetchAllWithReconnect(){
		this.db.reconnect();
		ObjectSet<SvnManager> results = this.db.fetchAll();
		
		assertsForFetchTests(results);
	}

	/**
	 * @param results
	 */
	private void assertsForFetchTests(ObjectSet<SvnManager> results) {
		assertNotNull("Los resultados son un gran NULL!",results);
		assertEquals("La cantidad de resultados no coincide", 1, results.size());
		SvnManager aSvnManager = results.get(0);
		assertNotNull("El primer resultado es un gran NULL!", aSvnManager);
		assertNotNull("Los usuarios son un gran NULL!", aSvnManager.getUsers());
		assertEquals("La cantidad de usuarios cargados no coincide", 2, aSvnManager.getUsers().size());
		assertNotNull("El primer resultado es un gran NULL!", aSvnManager.getUsers().get(0));
		assertEquals("El objeto usuario es NULL", "Foo, Bar", aSvnManager.getUsers().get(0).getName());
		assertEquals("El objeto usuario es NULL", "Bar, Foo", aSvnManager.getUsers().get(1).getName());
		assertNotNull("Los grupos son un gran NULL!", aSvnManager.getGroups());
		assertEquals("La cantidad de grupos cargados no coincide", 4, aSvnManager.getGroups().size());
		assertNotNull("El filesystem es un gran NULL!", aSvnManager.getFileSystem());
		assertNotNull("El filesystem es un gran NULL!", aSvnManager.getFileSystem().getChildren());
		assertEquals("La cantidad de carpetas en el filesystem no coincide", 3, aSvnManager.getFileSystem().getChildren().size());
		assertNotNull("La carpeta es un gran NULL!", aSvnManager.getFileSystem().getChildren().get(0));
		assertEquals("el nombre de la carpeta no coincide", "home", aSvnManager.getFileSystem().getChildren().get(0).getName());
		assertNotNull("La carpeta es un gran NULL!", aSvnManager.getFileSystem().getChildren().get(1));
		assertEquals("el nombre de la carpeta no coincide", "tmp", aSvnManager.getFileSystem().getChildren().get(1).getName());
		assertNotNull("La carpeta es un gran NULL!", aSvnManager.getFileSystem().getChildren().get(2));
		assertEquals("el nombre de la carpeta no coincide", "var", aSvnManager.getFileSystem().getChildren().get(2).getName());
	}
	
	public void testUpdate(){
		SvnManager aSvnManager = fetchOneSvnManager();
		
		setUpForUpdate(aSvnManager);
		
		try {
			this.db.save(aSvnManager);
		} catch (PersistenceException e) {
			fail();
		}
		
		aSvnManager = fetchOneSvnManager();
		
		assertsForUpdateTests(aSvnManager);
	}

	public void testUpdateWithReconnect(){
		SvnManager aSvnManager = fetchOneSvnManager();
		
		setUpForUpdate(aSvnManager);
		
		try {
			this.db.save(aSvnManager);
		} catch (PersistenceException e) {
			fail();
		}
		this.db.reconnect();
		
		aSvnManager = fetchOneSvnManager();
		
		assertsForUpdateTests(aSvnManager);
	}

	/**
	 * @param aSvnManager
	 */
	private void setUpForUpdate(SvnManager aSvnManager) {
		aSvnManager.getFileSystem().addChild(new Folder("etc"));
		aSvnManager.getFileSystem().getChildren().get(0).addChild(new Folder("gpilla"));
		aSvnManager.getFileSystem().getChildren().get(0).getChildren().get(0).addChild(new Folder("prueba"));
		aSvnManager.getFileSystem().getChildren().get(0).addChild(new Folder("lola"));
		try {
			aSvnManager.addUser(new User("John Doe", "jdoe", "pass"));
		} catch (UserCantBeCreated e) {
			fail();
		}
	}

	/**
	 * @param aSvnManager
	 */
	private void assertsForUpdateTests(SvnManager aSvnManager) {
		assertEquals("La cantidad de usuarios cargados no coincide", 3, aSvnManager.getUsers().size());
		assertNotNull("El primer resultado es un gran NULL!", aSvnManager.getUsers().get(2));
		assertEquals("El objeto usuario es NULL", "John Doe", aSvnManager.getUsers().get(2).getName());
		assertEquals("El objeto usuario es NULL", "jdoe", aSvnManager.getUsers().get(2).getId());
		assertEquals("El objeto usuario es NULL", "pass", aSvnManager.getUsers().get(2).getPass());
		
		assertEquals("La cantidad de carpetas en el filesystem no coincide", 4, aSvnManager.getFileSystem().getChildren().size());
		assertEquals("La cantidad de carpetas en el filesystem no coincide", 2, aSvnManager.getFileSystem().getChildren().get(0).getChildren().size());
		assertNotNull("La carpeta es un gran NULL!", aSvnManager.getFileSystem().getChildren().get(0).getChildren().get(0));
		assertEquals("el nombre de la carpeta no coincide", "gpilla", aSvnManager.getFileSystem().getChildren().get(0).getChildren().get(0).getName());
		assertNotNull("La carpeta es un gran NULL!", aSvnManager.getFileSystem().getChildren().get(0).getChildren().get(0).getChildren().get(0));
		assertNotNull("La carpeta es un gran NULL!", aSvnManager.getFileSystem().getChildren().get(0).getChildren().get(1));
		assertEquals("el nombre de la carpeta no coincide", "lola", aSvnManager.getFileSystem().getChildren().get(0).getChildren().get(1).getName());
		assertEquals("La cantidad de carpetas en el filesystem no coincide", 0, aSvnManager.getFileSystem().getChildren().get(1).getChildren().size());
	}
	
	
	// **********************************
	// ** Helpers
	// **********************************
	
	/**
	 * @return
	 */
	private SvnManager fetchOneSvnManager() {
		ObjectSet<SvnManager> results = this.db.fetchAll();
		SvnManager aSvnManager = results.next();
		return aSvnManager;
	}
}
